/*
 * monitor-process is parent-process
 * mainctrl-process is child-process
 */

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<wait.h>

#define _GNU_SOURCE
#include<pthread.h>

/* ipc */
#include<signal.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/ipc.h>

/* local */
#include"mainctrl.h"
#include"monitor.h"
#include<gpiox.h>
#include<global_header.h>
#include<wflyctrl.h>

/* public data */
int *plane_height;
int plane_already_land_flag;

pid_t monitor_pid;
pid_t mainctrl_pid;

/* private data, implementation */
//static int shm_id_plane_height;

static void gpio_exit_atexit(void) { gpio_exit(); }
static void wfly_stop_atexit(void) { wfly_stop(); }
#define illegal_mem_access() do{int *pt = NULL; *pt = 0;}while(0)

void test_plane_land_func(void) {
    int i;
    /* T = (val - 255) / 5.0,z
     * the range val of [260, 280] */
    wfly_lr_ctrl(0);
    wfly_fb_ctrl(0);
    for(i = 275; i >= 260; i -= 4) {
        int val_keep_time;
        val_keep_time = ((i - 255) / 10.0 );
        printf("\e[45;36;1m"
                "wfly_accel_down: val is %d.\t"
                "keep time is %d second.\t"
                "\e[0m\n",
                i, val_keep_time);
        wfly_accel_down(i);
        abs_usleep(val_keep_time * 1000 * 1000);
    }
}

static void monitor_force_stop_plane(void) {
        /* force to stop
         * cancel all mainctrl-threads
         * and it will cause to run `plane_emergency_land()'
         */
        kill(mainctrl_pid, SIGTERM);
        while(plane_already_land_flag == 0) {
            // abs_usleep(3 * 1000 * 1000);
            sleep(2); /* I don't know why `abs_usleep()' can't work */
        }

        /* delete the shared-memory ipc */
        //shmctl(shm_id_plane_height, IPC_RMID, NULL);

        /* cancel all other monitor-threads */
        // It seams to not easy to cancel.
        //pthread_cancel(monitor_tid_ary[MONITOR_TID_US100]);
        //pthread_tryjoin_np(monitor_tid_ary[MONITOR_TID_US100], NULL);
}

int main(int argc, char **argv) {
    int pid,    /* fork() return */
        ret,    /* common return */
        i;      /* common counter */

    /* common initialize */
    gpio_init();
    wfly_init();
    atexit(gpio_exit_atexit);
    atexit(wfly_stop_atexit);
    //atexit(test_plane_land_func);
    /* ipc init, plane height */
    //shm_id_plane_height = shmget(IPC_PRIVATE, sizeof(int), S_IWUSR | S_IRUSR);

    /* start to fork */
    if((pid = fork()) < 0) {
        perror("Error to fork():\n");
    } else if(pid > 0) { /* parent */
        /* `monitor' process entry */

        /* wait for `mainctrl' to __suspend__ */
        abs_usleep(2*1000*1000);

        /* obtain pids */
        monitor_pid = getpid();
        mainctrl_pid = pid;

        /* obtian the 'plane_height' pointer
         * in ipc-shared-mem */
        //plane_height = shmat(shm_id_plane_height, NULL, 0);

        /* register `mainctrl' die handler */
        signal(SIGCHLD, wait_child_to_die);

        /* create core threads */
        monitor_tid_ary[MONITOR_TID_WTD] = pthread_self();
        //pthread_create(&monitor_tid_ary[MONITOR_TID_US100], NULL, plane_height_detect, NULL);
        //abs_usleep(10 * 1000); /* wait for stable */

        /* initialize ready, wake up `mainctrl' */
        kill(mainctrl_pid, SIGCONT);

        /* watchdog thread */
#define Run_Time (60 * 5) /* second */
#define Run_Time_Factor 3
        /* sleep and then exit */
        for(i = 0; i < Run_Time; i++) {
            if((i + 1) % Run_Time_Factor == 0) {
                printf("\t\e[43;31;1m" "System has run %d second, will stop after %d second." "\e[0m\n",
                        i, (Run_Time - i));
            }
            //printf("\t\e[43;31;1m" "The height is %d cm." "\e[0m\n", *plane_height);
#if 0 /* us100 health detect */
            if(us100_health > 0)
                us100_health--;
            else {
                printf("\tus100-thread is dead, re-init.\n");
                pthread_create(&monitor_tid_ary[MONITOR_TID_US100],
                        NULL, plane_height_detect, NULL);
            }
#endif
            abs_usleep(1 * 1000 *1000);
        }

        /* time up, force plane to stop */
        monitor_force_stop_plane();

    } else { /* child */
        /* `mainctrl' process entry */

        /* suspend, wait it for monitor initialize,
         * wait for the wake-up signal */
        raise(SIGTSTP);

        /* obtain pids */
        monitor_pid = getppid();
        mainctrl_pid = getpid();

        /* obtian the 'plane_height' pointer in ipc-shared-mem */
        //plane_height = shmat(shm_id_plane_height, NULL, SHM_RDONLY);

        /* create core threads */
        pthread_create(&mainctrl_tid_ary[MAINCTRL_TID_POSRF],
                NULL, campos_refresh, NULL);
        usleep(2 * 1000 * 1000);
        pthread_create(&mainctrl_tid_ary[MAINCTRL_TID_MAIN],
                NULL, manipulate, NULL);

        while(1) {
            abs_usleep(5 * 1000 * 1000);
        }
    }

    return 0;
}
